home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BCI NET
/
BCI NET Dec 94.iso
/
archives
/
programming
/
libraries
/
newiff.lha
/
NewIFF
/
NewIFF39.lha
/
newiff39
/
modules
/
ilbmr.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-28
|
16KB
|
536 lines
/* ilbmr.c --- ILBM loading routines for use with iffparse */
/*----------------------------------------------------------------------*
* ILBMR.C Support routines for reading ILBM files.
* (IFF is Interchange Format File.)
*
* Based on code by Jerry Morrison and Steve Shaw, Electronic Arts.
* This software is in the public domain.
* Modified for iffparse.library 05/90
* This version for the Commodore-Amiga computer.
*
* 37.9 04/92
* 39.1 07/92 - add setcolors() and support for V39 color loading
* 39.2 09/92 - only check AllShifted for colors that are used.
* 39.3 09/92 - obey CMAPOK advisories
* 39.4 09/92 - fix CMAPOK code (39.3 bug was ignoring colors if bit set)
* 39.5 11/92 - add GetBitMapAttr/destWidthBytes check
* 39.7 1/93 - clear modeid before calculating one for bad/missing camg
*----------------------------------------------------------------------*/
#define INTUI_V36_NAMES_ONLY
#include "iffp/ilbm.h"
#include "iffp/packer.h"
#include "iffp/ilbmapp.h"
#define movmem CopyMem
#define MaxSrcPlanes (25)
extern struct Library *GfxBase;
/*---------- loadbody ---------------------------------------------------*/
LONG loadbody(iff, bitmap, bmhd)
struct IFFHandle *iff;
struct BitMap *bitmap;
BitMapHeader *bmhd;
{
BYTE *buffer;
ULONG bufsize;
LONG error = 1;
D(bug("In loadbody\n"));
if(!(currentchunkis(iff,ID_ILBM,ID_BODY)))
{
message(SI(MSG_ILBM_NOBODY)); /* Maybe it's a palette */
return(IFF_OKAY);
}
if((bitmap)&&(bmhd))
{
D(bug("Have bitmap and bmhd\n"));
bufsize = MaxPackedSize(RowBytes(bmhd->w)) << 4;
if(!(buffer = AllocMem(bufsize,0L)))
{
D(bug("Buffer alloc of %ld failed\n",bufsize));
return(IFFERR_NOMEM);
}
error = loadbody2(iff, bitmap, NULL, bmhd, buffer, bufsize);
D(bug("Returned from loadbody2, error = %ld\n",error));
}
FreeMem(buffer,bufsize);
return(error);
}
/* like the old GetBODY */
LONG loadbody2(iff, bitmap, mask, bmhd, buffer, bufsize)
struct IFFHandle *iff;
struct BitMap *bitmap;
BYTE *mask;
BitMapHeader *bmhd;
BYTE *buffer;
ULONG bufsize;
{
UBYTE srcPlaneCnt = bmhd->nPlanes; /* Haven't counted for mask plane yet*/
WORD srcRowBytes = RowBytes(bmhd->w);
WORD destRowBytes = bitmap->BytesPerRow; /* used as a modulo only */
LONG bufRowBytes = MaxPackedSize(srcRowBytes);
int nRows = bmhd->h;
WORD destWidthBytes; /* used for width check */
WORD compression = bmhd->compression;
register int iPlane, iRow, nEmpty;
register WORD nFilled;
BYTE *buf, *nullDest, *nullBuf, **pDest;
BYTE *planes[MaxSrcPlanes]; /* array of ptrs to planes & mask */
struct ContextNode *cn;
D(bug("loadbody2: srcRowBytes = %ld\n",srcRowBytes));
cn = CurrentChunk(iff);
if (compression > cmpByteRun1)
return(CLIENT_ERROR);
/* If >=V39, this may be an interleaved bitmap with a BytesPerRow
* which is truly just a modulo and actually includes ALL planes.
* So instead, for bounds checking, we use the pixel width of
* the BitMap rounded up to nearest WORD, since saved ILBMs
* are always saved as their width rounded up to nearest WORD.
*/
if(GfxBase->lib_Version >= 39)
{
destWidthBytes = RowBytes(GetBitMapAttr(bitmap,BMA_WIDTH));
}
else destWidthBytes = destRowBytes;
D(bug("loadbody2: compression=%ld srcBytes=%ld bitmapBytes=%ld\n",
compression, srcRowBytes, bitmap->BytesPerRow));
D(bug("loadbody2: bufsize=%ld bufRowBytes=%ld, srcPlaneCnt=%ld\n",
bufsize, bufRowBytes, srcPlaneCnt));
/* Complain if client asked for a conversion GetBODY doesn't handle.*/
if ( srcRowBytes > destWidthBytes ||
bufsize < bufRowBytes * 2 ||
srcPlaneCnt > MaxSrcPlanes )
return(CLIENT_ERROR);
D(bug("loadbody2: past conversion checks\n"));
if (nRows > bitmap->Rows) nRows = bitmap->Rows;
D(bug("loadbody2: srcRowBytes=%ld, srcRows=%ld, srcDepth=%ld, destDepth=%ld\n",
srcRowBytes, nRows, bmhd->nPlanes, bitmap->Depth));
/* Initialize array "planes" with bitmap ptrs; NULL in empty slots.*/
for (iPlane = 0; iPlane < bitmap->Depth; iPlane++)
planes[iPlane] = (BYTE *)bitmap->Planes[iPlane];
for ( ; iPlane < MaxSrcPlanes; iPlane++)
planes[iPlane] = NULL;
/* Copy any mask plane ptr into corresponding "planes" slot.*/
if (bmhd->masking == mskHasMask)
{
if (mask != NULL)
planes[srcPlaneCnt] = mask; /* If there are more srcPlanes than
* dstPlanes, there will be NULL plane-pointers before this.*/
else
planes[srcPlaneCnt] = NULL; /* In case more dstPlanes than src.*/
srcPlaneCnt += 1; /* Include mask plane in count.*/
}
/* Setup a sink for dummy destination of rows from unwanted planes.*/
nullDest = buffer;
buffer += srcRowBytes;
bufsize -= srcRowBytes;
/* Read the BODY contents into client's bitmap.
* De-interleave planes and decompress rows.
* MODIFIES: Last iteration modifies bufsize.*/
buf = buffer + bufsize; /* Buffer is currently empty.*/
for (iRow = nRows; iRow > 0; iRow--)
{
for (iPlane = 0; iPlane < srcPlaneCnt; iPlane++)
{
pDest = &planes[iPlane];
/* Establish a sink for any unwanted plane.*/
if (*pDest == NULL)
{
nullBuf = nullDest;
pDest = &nullBuf;
}
/* Read in at least enough bytes to uncompress next row.*/
nEmpty = buf - buffer; /* size of empty part of buffer.*/
nFilled = bufsize - nEmpty; /* this part has data.*/
if (nFilled < bufRowBytes)
{
/* Need to read more.*/
/* Move the existing data to the front of the buffer.*/
/* Now covers range buffer[0]..buffer[nFilled-1].*/
movmem(buf, buffer, nFilled); /* Could be moving 0 bytes.*/
if(nEmpty > ChunkMoreBytes(cn))
{
/* There aren't enough bytes left to fill the buffer.*/
nEmpty = ChunkMoreBytes(cn);
bufsize = nFilled + nEmpty; /* heh-heh */
}
/* Append new data to the existing data.*/
if(ReadChunkBytes(iff, &buffer[nFilled], nEmpty) < nEmpty)
return(CLIENT_ERROR);
buf = buffer;
nFilled = bufsize;
nEmpty = 0;
}
/* Copy uncompressed row to destination plane.*/
if(compression == cmpNone)
{
if(nFilled < srcRowBytes) return(IFFERR_MANGLED);
movmem(buf, *pDest, srcRowBytes);
buf += srcRowBytes;
*pDest += destRowBytes;
}
else
{
/* Decompress row to destination plane.*/
if ( unpackrow(&buf, pDest, nFilled, srcRowBytes) )
/* pSource, pDest, srcBytes, dstBytes */
return(IFFERR_MANGLED);
else *pDest += (destRowBytes - srcRowBytes);
}
}
}
return(IFF_OKAY);
}
/* ----------- getcolors ------------- */
/* getcolors - allocates a ilbm->colortable for at least 32 registers
* and loads CMAP colors into it, setting ilbm->ncolors to number
* of colors actually loaded.
*
* V39 and above: unless ilbm->IFFPFlags & IFFPF_NOCOLOR32, will also
* allocate and build a 32-bit per gun colortable (ilbm->colortable32)
* and ilbm->colorrecord for LoadRGB32().
*/
LONG getcolors(struct ILBMInfo *ilbm)
{
struct IFFHandle *iff;
LONG error;
if(!(iff=ilbm->ParseInfo.iff)) return(CLIENT_ERROR);
if(!(error = alloccolortable(ilbm)))
error = loadcmap(ilbm);
if(error) freecolors(ilbm);
D(bug("getcolors: error = %ld\n",error));
return(error);
}
/* alloccolortable - allocates ilbm->colortable and sets ilbm->ncolors
* to the number of colors we have room for in the table.
*
* V39 and above: unless ilbm->IFFPFlags & IFFPF_NOCOLOR32, will also
* allocate and build a 32-bit per gun colortable (ilbm->colortable32)
* and ilbm->colorrecord for LoadRGB32()
*/
LONG alloccolortable(struct ILBMInfo *ilbm)
{
struct IFFHandle *iff;
struct StoredProperty *sp;
LONG error = CLIENT_ERROR;
ULONG ctabsize;
USHORT ncolors;
if(!(iff=ilbm->ParseInfo.iff)) return(CLIENT_ERROR);
if(sp = FindProp (iff, ID_ILBM, ID_CMAP))
{
/*
* Compute the size table we need
*/
ncolors = sp->sp_Size / 3; /* how many in CMAP */
ncolors = MAX(ncolors, 32); /* alloc at least 32 */
ctabsize = ncolors * sizeof(Color4);
if(ilbm->colortable =
(Color4 *)AllocMem(ctabsize,MEMF_CLEAR|MEMF_PUBLIC))
{
ilbm->ncolors = ncolors;
ilbm->ctabsize = ctabsize;
error = 0L;
if((GfxBase->lib_Version >= 39)&&
(!(ilbm->IFFPFlags & IFFPF_NOCOLOR32)))
{
ctabsize = (ncolors * sizeof(Color32))+(4 * sizeof(WORD));
if(ilbm->colorrecord = (WORD *)
AllocMem(ctabsize,MEMF_CLEAR|MEMF_PUBLIC))
{
ilbm->crecsize = ctabsize;
ilbm->colortable32 = (Color32 *)(&ilbm->colorrecord[2]);
ilbm->colorrecord[0] = ncolors; /* For LoadRGB32 */
ilbm->colorrecord[1] = 0;
}
else error = IFFERR_NOMEM;
}
}
else error = IFFERR_NOMEM;
}
D(bug("alloccolortable for %ld colors: error = %ld\n",ncolors,error));
if(error) freecolors(ilbm);
return(error);
}
void freecolors(struct ILBMInfo *ilbm)
{
if(ilbm->colortable)
{
FreeMem(ilbm->colortable, ilbm->ctabsize);
}
ilbm->colortable = NULL;
ilbm->ctabsize = 0;
if(ilbm->colorrecord)
{
FreeMem(ilbm->colorrecord, ilbm->crecsize);
}
ilbm->colorrecord = NULL;
ilbm->colortable32 = NULL;
ilbm->crecsize = 0;
}
/* loadcmap - note interface change for V39
*
* Passed ILBMInfo
*
* Sets ncolors (and colorrecord if using it) to the number actually read.
*
* New for V39 and above: If bmhd->flags BMHDF_CMAPOK is set,
* or if ILBMInfo->IFFPFlags IFFPF_CMAPOK is set, the 32-bit gun code
* will assume the CMAP contains 8-bit significant guns (R,G,B)
* and will not scale apparent 4-bit nibbles to 8 bits prior to
* scaling to 32 bits. In the absence of either of these flags,
* if whole usable CMAP contains RGB values whose low nibbles are all 0,
* this code will first scale the RGB values to 8 bits ($30 becomes $33, etc)
*/
LONG loadcmap(struct ILBMInfo *ilbm)
{
struct StoredProperty *sp;
LONG k;
ULONG ncolors, gun, ncheck;
UBYTE *rgb, rb, gb, bb;
ULONG nc, r, g, b;
struct IFFHandle *iff;
BOOL AllShifted;
if(!(iff=ilbm->ParseInfo.iff)) return(CLIENT_ERROR);
if(!(ilbm->colortable))
{
message(SI(MSG_ILBM_NOCOLORS));
return(1);
}
if(!(sp = FindProp (iff, ID_ILBM, ID_CMAP))) return(1);
rgb = sp->sp_Data;
/* file has this many colors */
nc = sp->sp_Size / sizeofColorRegister;
ncolors = nc;
/* if ILBMInfo can't hold that many, we'll load less */
if(ilbm->ncolors < ncolors) ncolors = ilbm->ncolors;
/* set to how many we are loading */
ilbm->ncolors = ncolors;
/* how many colors to check for shifted nibbles (i.e. used colors) */
ncheck = 1 << ilbm->Bmhd.nPlanes;
if(ncheck > ncolors) ncheck = ncolors;
if((GfxBase->lib_Version >= 39)
&& (!(ilbm->IFFPFlags & IFFPF_NOCOLOR32))
&&(ilbm->colorrecord))
{
ilbm->colorrecord[0] = ncolors;
/* Assign to 32-bit table, examine for all-shifted nibbles at same time */
AllShifted = TRUE;
k = 0;
while (ncheck--)
{
ilbm->colortable32[k].r = rb = *rgb++;
ilbm->colortable32[k].g = gb = *rgb++;
ilbm->colortable32[k].b = bb = *rgb++;
if(((rb & 0x0F) || (gb & 0x0F) || (bb & 0x0F)))
AllShifted=FALSE;
k++;
}
/* If no file/user indication that this is an 8-bit significant CMAP... */
if( (!(ilbm->IFFPFlags & IFFPF_CMAPOK)) &&
(!(ilbm->Bmhd.flags & BMHDF_CMAPOK)) )
{
/* If all nibbles appear shifted (4 bit), duplicate the nibbles */
if(AllShifted)
{
for(k = 0; k <nc; k++)
{
ilbm->colortable32[k].r |= (ilbm->colortable32[k].r >> 4);
ilbm->colortable32[k].g |= (ilbm->colortable32[k].g >> 4);
ilbm->colortable32[k].b |= (ilbm->colortable32[k].b >> 4);
}
}
}
/* Now scale to 32 bits */
for(k = 0; k <nc; k++)
{
gun = ilbm->colortable32[k].r;
ilbm->colortable32[k].r |= ((gun << 24) | (gun << 16) | (gun << 8));
gun = ilbm->colortable32[k].g;
ilbm->colortable32[k].g |= ((gun << 24) | (gun << 16) | (gun << 8));
gun = ilbm->colortable32[k].b;
ilbm->colortable32[k].b |= ((gun << 24) | (gun << 16) | (gun << 8));
}
}
/* always make old-style table */
rgb = sp->sp_Data;
ncolors = nc;
k = 0;
while (ncolors--)
{
r = (*rgb++ & 0xF0) << 4;
g = *rgb++ & 0xF0;
b = *rgb++ >> 4;
ilbm->colortable[k] = r | g | b;
k++;
}
return(0);
}
/* setcolors - sets vp to ilbm->colortable or ilbm->colortable32
*
* V39 and above: unless ilbm->IFFPFlags & IFFPF_NOCOLOR32, will
* use 32-bit per gun colortable (ilbm->colortable32) and functions
*
* Returns client error if there is no ilbm->vp
*/
LONG setcolors(struct ILBMInfo *ilbm, struct ViewPort *vp)
{
LONG nc;
LONG error = 0L;
if(!(vp)) return(CLIENT_ERROR);
nc = MIN(ilbm->ncolors,vp->ColorMap->Count);
if((GfxBase->lib_Version >= 39)&&
(! (ilbm->IFFPFlags & IFFPF_NOCOLOR32))&&
(ilbm->colorrecord))
{
LoadRGB32(vp, (ULONG *)ilbm->colorrecord);
}
else if(ilbm->colortable)
{
LoadRGB4(vp, ilbm->colortable, nc);
}
error = CLIENT_ERROR;
return(error);
}
/*
* Returns CAMG or computed mode for storage in ilbm->camg
*
* ilbm->Bmhd structure must be initialized prior to this call.
*/
ULONG getcamg(struct ILBMInfo *ilbm)
{
struct IFFHandle *iff;
struct StoredProperty *sp;
UWORD wide,high,deep;
ULONG modeid = 0L;
if(!(iff=ilbm->ParseInfo.iff)) return(0L);
wide = ilbm->Bmhd.pageWidth;
high = ilbm->Bmhd.pageHeight;
deep = ilbm->Bmhd.nPlanes;
D(bug("Getting CAMG for pic w=%ld h=%ld d=%ld ILBM\n",wide,high,deep));
/*
* Grab CAMG's idea of the viewmodes.
*/
if (sp = FindProp (iff, ID_ILBM, ID_CAMG))
{
modeid = (* (ULONG *) sp->sp_Data);
D(bug("Found CAMG containing $%08lx\n",modeid));
/* knock bad bits out of old-style 16-bit viewmode CAMGs
*/
if((!(modeid & MONITOR_ID_MASK))||
((modeid & EXTENDED_MODE)&&(!(modeid & 0xFFFF0000))))
modeid &=
(~(EXTENDED_MODE|SPRITES|GENLOCK_AUDIO|GENLOCK_VIDEO|VP_HIDE));
D(bug("Filter1: CAMG now $%08lx\n",modeid));
/* check for bogus CAMG like DPaintII brushes
* with junk in upper word and extended bit
* not set in lower word.
*/
if((modeid & 0xFFFF0000)&&(!(modeid & 0x00001000))) sp=NULL;
D(bug("Filter2: CAMG is %s\n", sp ? "OK" : "NOT OK"));
}
if(!sp) {
/*
* No CAMG (or bad CAMG) present; use computed modes.
*/
modeid = 0L; /* added in 39.6 */
if (wide >= 640) modeid = HIRES;
if (high >= 400) modeid |= LACE;
if (deep == 6)
{
modeid |= ilbm->EHB ? EXTRA_HALFBRITE : HAM;
}
D(bug("No CAMG found - using mode $%08lx\n",modeid));
}
if(ilbm->IFFPFlags & IFFPF_NOMONITOR) modeid &= (~MONITOR_ID_MASK);
D(bug("getcamg: modeid = $%08lx\n",modeid));
return(modeid);
}